import json
import re

from django.shortcuts import render

# Create your views here.

# 具体的看qq开放平台关于qq第三方登录的文档
"""
3.1 准备工作
    qq登录参数:我们申请的客户端id QQ_CLIENT_ID
            :我们申请的客户端密钥 QQ_CLIENT_SECRET
            :我们申请时添加的:登录成功后返回的路径 QQ_REDIRECT_URI
3.2 设置qq登录的图标   前端已经设置好了
3.3 根据oauth2.0 来获取code 和 token  我们要做的
    对于应用而言，需要进行两步:
    1. 获取Authorization Code 表面是一个链接，实质是需要用户同意，然后获取code
    2. 通过Authorization Code 获取Access Token
3.4 通过token获取 openid    我们要做的
    openid 是此网站上唯一对应用户身份的标识，网站可将此ID进行存储便于下次登录时辨识其身份，
    或将其与用户在网站上的原有账号进行绑定
把openid 和 用户信息进行一一对应的绑定
生成用户绑定链接--->>获取code--->>获取token--->>获取openid--->>保存openid
"""

# 1.首先安装QQLoginTool
# pip install QQLoginTool
"""
生成用户绑定链接

前端: 当用户点击qq登录图标时，前端会发送一个axios(Ajax)请求

后端:
    请求
    业务逻辑    调用QQLoginTool 生成跳转链接
    响应       返回跳转链接{"code":0, "qq_login_url":"http://xxx"}
    路由       GET qq/authorization/
    步骤
        # 1. 生成 QQLoginTool 实例对象
        # 2. 调用对象的方法生成跳转链接
        # 3. 返回响应

404 路由不匹配
405 方法不被允许(你没有实现请求对应的方法)
"""
from django.views import View
from QQLoginTool.QQtool import OAuthQQ
from meiduo_mall import settings
from django.http import JsonResponse


class QQLoginView(View):

    def get(self, request):
        # 1. 生成 QQLoginTool 实例对象
        # client_id=None,       appid
        # client_secret=None,   appsecret
        # 上面两个参数需要去qq开放平台申请
        # redirect_uri=None,    用户登录之后跳转的页面
        # state=None
        # 我们将上面的参数写入到配置文件settings中，方便后续更改，使用时只需要导入即可
        qq = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                     client_secret=settings.QQ_CLIENT_SECRET,
                     redirect_uri=settings.QQ_REDIRECT_URI,
                     state='xxxxx')

        # 2. 调用对象的方法生成跳转链接
        qq_login_url = qq.get_qq_url()

        # 3. 返回响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'login_url': qq_login_url})


"""
美多账号绑定qq账号

需求: 获取code，通过code换取token，再通过token换取openid
前端:
    应该获取用户同意登录的code，把这个code发送给后端
后端:
    请求  获取code
    业务逻辑    通过code换取token，再通过token换取openid
              根据openid进行判断
              如果没有绑定过，则需要绑定
              如果绑定过，则直接登录
    响应
    路由      GET   oauth_callback/?code=xxxxx
    步骤 
        1. 获取code
        2. 通过code换取token
        3. 再通过token换取openid
        4. 根据openid进行判断
        5. 如果没有绑定过，则需要绑定
        6. 如果绑定过，则直接登录         
"""

"""
需求: 绑定qq(openid) 和 美多的账号信息

前端: 
    当用户输入手机号，密码，短信验证码之后就发送axios请求，
    请求需要携带 mobile,password,sms_code,access_token(openid)
后端:
    请求: 接收请求，获取请求参数
    业务逻辑: 绑定，完成状态保持
    路由: POST    oauth_callback/
    步骤:
        1. 接收请求
        2. 获取请求参数 openid
        3. 根据手机号进行用户信息的查询
        4. 查询到用户手机号已经注册过了，就可以直接保持(绑定) 用户和openid信息
        5. 查询到用户手机号没有被注册 我们就创建一个user信息，然后再绑定
        6. 完成状态保持
        7. 返回响应
"""

# 实现qq与美多号绑定
from apps.oauth.models import OAuthQQUser
from django.contrib.auth import login
from apps.users.models import User
from apps.oauth.utils import check_access_token, generic_openid


class OauthQQView(View):
    def get(self, request):
        # 1. 获取code
        code = request.GET.get('code')
        if code is None:
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})

        # 2. 通过code换取token
        qq = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                     client_secret=settings.QQ_CLIENT_SECRET,
                     redirect_uri=settings.QQ_REDIRECT_URI,
                     state='xxxxx')
        token = qq.get_access_token(code)

        # 3. 再通过token换取openid
        openid = qq.get_open_id(token)

        # 4. 根据openid进行判断
        try:
            qquser = OAuthQQUser.objects.get(openid=openid)
        except OAuthQQUser.DoesNotExist:
            # 4.1 如果不存在则需要绑定
            # 对openid进行加密
            access_token = generic_openid(openid)

            response = JsonResponse({'code': 400, 'access_token': access_token})
            return response
        else:
            # 4.2 如果存在则直接登录
            # 状态保持
            # 设置session
            login(request, qquser.user)
            # 设置cookie
            response = JsonResponse({'code': 0, 'errmsg': 'ok'})
            response.set_cookie('username', qquser.user.username)
            return response

    def post(self, request):
        # 1. 接收请求
        data = json.loads(request.body)

        # 2. 获取请求参数 openid
        mobile = data.get('mobile')
        password = data.get('password')
        sms_code = data.get('sms_code')
        access_token = data.get('access_token')

        # 添加对access_token 解密
        openid = check_access_token(access_token)
        if openid is None:
            return JsonResponse({'code': 400, 'errmsg': '参数缺失!'})

        # 判断是否缺数据
        if not all([mobile, password, sms_code, openid]):
            return JsonResponse({'code': 400, 'errmsg': '参数不全!'})

        # 手机号满足规则且不能重复
        if not re.match('^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '手机号不符合规则'})

        # 密码满足规则
        if len(password) < 8 or len(password) > 20:
            return JsonResponse({'code': 400, 'errmsg': '密码不符合规则'})

        # 验证短信验证码
        from django_redis import get_redis_connection
        redis_cli = get_redis_connection('verify_code')
        # 从redis中拿到短信验证码
        redis_sms_code = redis_cli.get(mobile).decode()
        if redis_sms_code is None:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码已过期！'})
        if redis_sms_code != sms_code:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码错误，请重试！'})

        # 3. 根据手机号进行用户信息的查询
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            # 4. 查询到用户手机号没有被注册 我们就创建一个user信息，然后再绑定
            user = User.objects.create_user(username=mobile, mobile=mobile, password=password)
        else:
            # 5. 查询到用户手机号已经注册过了但是密码不对
            if not user.check_password(password):
                return JsonResponse({'code': 400, 'errmsg': '账号或者密码错误'})

        # 6. 保持(绑定) 用户和openid信息
        OAuthQQUser.objects.create(user=user, openid=openid)

        # 6. 完成状态保持
        login(request, user)
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.set_cookie('username', user.username)

        # 7. 返回响应
        return response


# openid 给前端后是公开的,对于敏感数据应该加密
# itsdangerous是为了给数据加密的






